В коде рисования Вы будете использовать функции sin и cos чтобы вычислить точки многоугольника. Для использования этих функций необходимо включение math.h в PolyCtl.h:
#include <math.h> #include "resource.h" // main symbols
Внимание только для Release builds. Когда ATL COM AppWizard генерирует проект задана по умолчанию макродиректива _ATL_MIN_CRT. Эта макрокоманда определена так, чтобы не использовать C Run-Time Library в вашем коде если Вы не нуждаетесь в ней. Элемент управления многоугольник нуждается в коде C Run-Time Library чтобы инициализировать функции работы с плавающей запятой. Следовательно Вы должны удалить _ATL_MIN_CRT макрокоманду если Вы хотите формировать Release версию. Чтобы удалить макрокоманду нажмите Settings в меню Project. В Settings For: раскрывающимся списке выберите Multiple Configurations. В Select project configuration(s) to modify диалоговом окне которое появиться нажмите переключатели для всех четырех Release версий, затем нажмите OK. На вкладке C/C++ выберите General категорию, затем удалите _ATL_MIN_CRT из окна редактирования определений (definitions) препроцессора.
Как только точки многоугольника вычислены Вы должны их сохранять. Добавьте массив типа POINT в конец определения класса PolyCtl.h:
OLE_COLOR m_clrFillColor; short m_nSides; POINT m_arrPoint[100];
Теперь измените функцию OnDraw в PolyCtl.h как в коде ниже. Обратите внимание что Вы удаляете обращения к функциям Rectangle и DrawText. Вы также явно получаете и выбираете черную и белую кисть. Если окно не Ваше собственное Вы не можете делать предположения относительно контекста устройства в котором вы будете рисовать.
Завершенный OnDraw выглядит следующим образом:
HRESULT CPolyCtl::OnDraw(ATL_DRAWINFO& di)
{
RECT& rc = *(RECT*)di.prcBounds;
HDC hdc = di.hdcDraw;
COLORREF colFore;
HBRUSH hOldBrush, hBrush;
HPEN hOldPen, hPen;
// Translate m_colFore into a COLORREF type
OleTranslateColor(m_clrFillColor, NULL, &colFore);
// Create and select the colors to draw the circle
hPen = (HPEN)GetStockObject(BLACK_PEN);
hOldPen = (HPEN)SelectObject(hdc, hPen);
hBrush = (HBRUSH)GetStockObject(WHITE_BRUSH);
hOldBrush = (HBRUSH)SelectObject(hdc, hBrush);
Ellipse(hdc, rc.left, rc.top, rc.right, rc.bottom);
// Create and select the brush that will be used to fill the polygon
hBrush = CreateSolidBrush(colFore);
SelectObject(hdc, hBrush);
CalcPoints(rc);
Polygon(hdc, &m_arrPoint[0], m_nSides);
// Select back the old pen and brush and delete the brush we created
SelectObject(hdc, hOldPen);
SelectObject(hdc, hOldBrush);
DeleteObject(hBrush);
return S_OK;
}
Вы теперь должны добавить функцию с именем CalcPoints которая вычислит координаты пересечений линий. Эти вычисления будут основаны на переменной RECT которая передана в функцию. Сначала Вы должны добавить описание CalcPoints в общий раздел для класса IPolyCtl в PolyCtl.h:
void CalcPoints(const RECT& rc);
Общий раздел класса IPolyCtl должен теперь выглядеть следующим образом:
// IPolyCtl public: STDMETHOD(get_Sides)(/*[out, retval]*/ short *newVal); STDMETHOD(put_Sides)(/*[in]*/ short newVal); void CalcPoints(const RECT& rc);
Затем добавьте реализацию функции CalcPoints в конец PolyCtl.cpp файла:
void CPolyCtl::CalcPoints(const RECT& rc)
{
const double pi = 3.14159265358979;
POINT ptCenter;
double dblRadiusx = (rc.right - rc.left) / 2;
double dblRadiusy = (rc.bottom - rc.top) / 2;
double dblAngle = 3 * pi / 2; // Start at the top
double dblDiff = 2 * pi / m_nSides; // Angle each side will make
ptCenter.x = (rc.left + rc.right) / 2;
ptCenter.y = (rc.top + rc.bottom) / 2;
// Calculate the points for each side
for (int i = 0; i < m_nSides; i++)
{
m_arrPoint[i].x = (long)(dblRadiusx * cos(dblAngle) + ptCenter.x + 0.5);
m_arrPoint[i].y = (long)(dblRadiusy * sin(dblAngle) + ptCenter.y + 0.5);
dblAngle += dblDiff;
}
}
Инициализируйте m_clrFillColor. Выберите зеленый как заданный по умолчанию цвет и добавьте строку ниже в CPolyCtl конструктор в файле PolyCtl.h:
m_clrFillColor = RGB(0, 0xFF, 0);
Конструктор теперь должен выглядеть следующим образом:
CPolyCtl()
{
m_nSides = 3;
m_clrFillColor = RGB(0, 0xFF, 0);
}
Дальше соберите снова элемент управления. Откройте ActiveX Control Test Container и вставьте элемент управления. Вы должны видеть зеленый треугольник внутри круга.
Пробуйте изменить число сторон. Чтобы изменять свойство в двойном
(dual) интерфейсе из Test Container используйте Invoke
Methods:
1.В Test Container щелкните Invoke Methods в
Control меню. Диалоговое окно Invoke Method
появиться.
2.Выберите PropPut версию свойства Sides из
Method Name.
3.Напечатайте 5 в окне редактирования Parameter
Value, нажмите Set Value и щелкните по Invoke.

Обратите внимание что элемент управления не изменяется. Что же неправильно? Хотя Вы изменил число сторон устанавливая m_nSides переменную, Вы не заставляли элемент управления повторно перерисовываться. Если Вы переключись на другое приложение и затем вернетесь обратно чтобы проверить контейнер, Вы увидите что элемент управления повторно окрашен и теперь имеет правильное число сторон.Чтобы исправить эту проблему Вы должны добавить обращение к функции FireViewChange которая определена в IViewObjectExImpl после того как Вы устанавливаете число сторон. Если элемент управления выполняется в собственном окне, FireViewChange вызовет InvalidateRect API. Если элемент управления выполняет без своего окна, InvalidateRect метод будет вызван из интерфейса контейнера.
Новый put_Sides метод следующий:
STDMETHODIMP CPolyCtl::put_Sides(short newVal)
{
if (newVal > 2 && newVal < 101)
{
m_nSides = newVal;
FireViewChange();
return S_OK;
}
else
return Error(_T("Shape must have between 3 and 100 sides"));
}
После того, как вы добавили FireViewChange соберите элемент управления снова. На сей раз когда Вы изменяете число сторон и щелкаете Invoke, Вы должны немендленно видеть изменения.